#ifndef WLC_DILITHIUM_PARAMS_H_
#define WLC_DILITHIUM_PARAMS_H_

#include <stddef.h>
#include "config.h"

/*============================================================================*/
/* Macro definitions                                                          */
/*============================================================================*/


#define SEEDBYTES 32
#define CRHBYTES 48
#define N 256
#define Q 8380417
#define D 13
#define ROOT_OF_UNITY 1753

#define LV2_K 4
#define LV2_L 4
#define LV2_ETA 2
#define LV2_TAU 39
#define LV2_BETA 78
#define LV2_GAMMA1 (1 << 17)
#define LV2_GAMMA2 ((Q-1)/88)
#define LV2_OMEGA 80

#define LV3_K 6
#define LV3_L 5
#define LV3_ETA 4
#define LV3_TAU 49
#define LV3_BETA 196
#define LV3_GAMMA1 (1 << 19)
#define LV3_GAMMA2 ((Q-1)/32)
#define LV3_OMEGA 55

#define LV5_K 8
#define LV5_L 7
#define LV5_ETA 2
#define LV5_TAU 60
#define LV5_BETA 120
#define LV5_GAMMA1 (1 << 19)
#define LV5_GAMMA2 ((Q-1)/32)
#define LV5_OMEGA 75

#define POLYT1_PACKEDBYTES  320
#define POLYT0_PACKEDBYTES  416
// #define POLYVECH_PACKEDBYTES (OMEGA + K)
#define MAX_POLYVECH_PACKEDBYTES (LV5_OMEGA + LV5_K)

/*
// #if GAMMA1 == (1 << 17)
// #define POLYZ_PACKEDBYTES   576
// #elif GAMMA1 == (1 << 19)
// #define POLYZ_PACKEDBYTES   640
// #endif
*/
#define MAX_POLYZ_PACKEDBYTES 640

/*
// #if GAMMA2 == (Q-1)/88
// #define POLYW1_PACKEDBYTES  192
// #elif GAMMA2 == (Q-1)/32
// #define POLYW1_PACKEDBYTES  128
// #endif
*/
#define MAX_POLYW1_PACKEDBYTES 192

/*
// #if ETA == 2
// #define POLYETA_PACKEDBYTES  96
// #elif ETA == 4
// #define POLYETA_PACKEDBYTES 128
// #endif
*/
#define MAX_POLYETA_PACKEDBYTES 128

/*
// #define CRYPTO_PUBLICKEYBYTES (SEEDBYTES + K*POLYT1_PACKEDBYTES)
// #define CRYPTO_SECRETKEYBYTES (2*SEEDBYTES + CRHBYTES \
//                                + L*POLYETA_PACKEDBYTES \
//                                + K*POLYETA_PACKEDBYTES \
//                                + K*POLYT0_PACKEDBYTES)
// #define CRYPTO_BYTES (SEEDBYTES + L*POLYZ_PACKEDBYTES + POLYVECH_PACKEDBYTES)
*/
#define MAX_L LV5_L
#define MAX_K LV5_K

#define MAX_CRYPTO_PUBLICKEYBYTES (SEEDBYTES + MAX_K*POLYT1_PACKEDBYTES)
#define MAX_CRYPTO_SECRETKEYBYTES (2*SEEDBYTES + CRHBYTES \
                               + MAX_L*MAX_POLYETA_PACKEDBYTES \
                               + MAX_K*MAX_POLYETA_PACKEDBYTES \
                               + MAX_K*POLYT0_PACKEDBYTES)
#define MAX_CRYPTO_BYTES (SEEDBYTES + MAX_L*MAX_POLYZ_PACKEDBYTES + MAX_POLYVECH_PACKEDBYTES)

/*============================================================================*/
/* Constant definitions                                                       */
/*============================================================================*/

typedef struct dilithium_params_
{
    int K;
    int L;
    int ETA;
    int TAU;
    int BETA;
    int GAMMA1;
    int GAMMA2;
    int OMEGA;

    /* POLYVECH_PACKEDBYTES (OMEGA + K) */
    int POLYVECH_PACKEDBYTES;

    /**
     *  #if GAMMA1 == (1 << 17)
     *      #define POLYZ_PACKEDBYTES   576
     *  #elif GAMMA1 == (1 << 19)
     *      #define POLYZ_PACKEDBYTES   640
     *  #endif
     * */
    int POLYZ_PACKEDBYTES;

    /**
     *  #if GAMMA2 == (Q-1)/88
     *      #define POLYW1_PACKEDBYTES  192
     *  #elif GAMMA2 == (Q-1)/32
     *      #define POLYW1_PACKEDBYTES  128
     *  #endif
     * */
    int POLYW1_PACKEDBYTES;

    /**
     * #if ETA == 2
     * #define POLYETA_PACKEDBYTES  96
     * #elif ETA == 4
     * #define POLYETA_PACKEDBYTES 128
     * #endif
    */
    int POLYETA_PACKEDBYTES;

    /* SEEDBYTES + K*POLYT1_PACKEDBYTES */
    int CRYPTO_PUBLICKEYBYTES;

    /**
     * #define CRYPTO_SECRETKEYBYTES (2*SEEDBYTES + CRHBYTES + L*POLYETA_PACKEDBYTES + K*POLYETA_PACKEDBYTES + K*POLYT0_PACKEDBYTES)
    */
    int CRYPTO_SECRETKEYBYTES;

    /* SEEDBYTES + L*POLYZ_PACKEDBYTES + POLYVECH_PACKEDBYTES */
    int CRYPTO_BYTES;
} dilithium_params;

extern int dilithium_level;
extern dilithium_params params;


/*============================================================================*/
/* Function definitions                                                        */
/*============================================================================*/

#ifdef __cplusplus
extern "C"
{ /* start of __cplusplus */
#endif

    /**
     * init dilithium parameters
    */
int dilithium_init(int level);

#ifdef __cplusplus
} /* end of __cplusplus */
#endif

#endif /* WLC_DILITHIUM_PARAMS_H_ */
